package org.krayne.swivel.list;

import java.awt.BorderLayout;
import java.awt.Font;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import java.util.Collection;

import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.ListCellRenderer;
import javax.swing.event.ListDataListener;
import javax.swing.event.ListSelectionListener;

import org.krayne.swivel.filter.SimpleStringFilter;
import org.krayne.swivel.filter.SimpleStringFilterListener;
import org.krayne.swivel.filter.SimpleStringFilterPanel;

/**
 * A panel that has a string-filterable list.
 * 
 * @author dhsu
 */
public class FilterListPanel extends JPanel {
    private static final long serialVersionUID = 1938974152517306413L;
    
    private final SimpleStringFilterPanel filterPanel;
    private final JList filteredList;
    private FilterListModel listModel;
    
    /**
     * Constructs an empty filterable list.
     */
    public FilterListPanel() {
        this(new Object[] {});
    }
    
    /**
     * Constructs a filterable list with the specified items.
     * 
     * @param listData the items to initialize the list with
     */
    public FilterListPanel(Collection<?> listData) {
        this(listData.toArray());
    }
    
    /**
     * Constructs a filterable list with the specified items.
     * 
     * @param listData the items to initialize the list with
     */
    public FilterListPanel(Object[] listData) {
        super(new BorderLayout());
        this.filterPanel = new SimpleStringFilterPanel();
        this.filteredList = new JList();
        
        // create and set the list model
        this.listModel = new FilterListModel(filterPanel.getFilter());
        for(Object item : listData) {
            listModel.addElement(item);
        }
        this.filteredList.setModel(listModel);
        
        // listen to filter panel's filter changes, update list model accordingly
        this.filterPanel.addFilterListener(new SimpleStringFilterListener() {
            public void filterChanged(SimpleStringFilter newFilter) {
                listModel.setFilter(newFilter);
            }
        });
        
        // layout
        JScrollPane listScrollPane = new JScrollPane(filteredList);
        this.add(filterPanel, BorderLayout.NORTH);
        this.add(listScrollPane, BorderLayout.CENTER);
    }
    
    /**
     * {@inheritDoc}
     */
    public void setFont(Font font) {
        super.setFont(font);
        
        if(filterPanel != null) {
            filterPanel.setFont(font);
        }
        
        if(filteredList != null) {
            filteredList.setFont(font);
        }
    }

    /**
     * Sets the elements of the list.
     * 
     * @param listData the list items
     */
    public void setListData(Collection<?> listData) {
        this.setListData(listData.toArray());
    }
    
    /**
     * Sets the elements of the list.
     * 
     * @param listData the list items
     */
    public void setListData(Object[] listData) {
        this.listModel = new FilterListModel(filterPanel.getFilter());
        for(Object item : listData) {
            listModel.addElement(item);
        }
        this.filteredList.setModel(listModel);
    }

    //--------------------------------------------------------------------------
    // methods delegated directly to the SimpleStringFilterPanel
    
    public SimpleStringFilter getFilter() {
        return this.filterPanel.getFilter();
    }
    
    //--------------------------------------------------------------------------
    // methods delegated directly to the FilterListModel
    
    public void addListDataListener(ListDataListener l) {
        this.listModel.addListDataListener(l);
    }
    
    public void addElement(Object element) {
        this.listModel.addElement(element);
    }

    public Object getElementAt(int index) {
        return this.listModel.getElementAt(index);
    }
    
    public Collection<Object> getFilteredElements() {
        return this.listModel.getFilteredElements();
    }
    
    public Object getUnfilteredElementAt(int index) {
        return this.listModel.getUnfilteredElementAt(index);
    }
    
    public Collection<Object> getUnfilteredElements() {
        return this.listModel.getUnfilteredElements();
    }
    
    public int getNumPassingElements() {
        return this.listModel.getSize();
    }
    
    public int getTotalNumElements() {
        return this.listModel.getUnfilteredSize();
    }
    
    public void removeAllElements() {
        this.listModel.removeAllElements();
    }
    
    public void removeElement(Object element) {
        this.listModel.removeElement(element);
    }
    
    public void removeListDataListener(ListDataListener l) {
        this.listModel.removeListDataListener(l);
    }
    
    //--------------------------------------------------------------------------
    // methods delegated directly to the JList
    
    public void addListMouseListener(MouseListener l) {
        this.filteredList.addMouseListener(l);
    }
    
    public void addListMouseMotionListener(MouseMotionListener l) {
        this.filteredList.addMouseMotionListener(l);
    }
    
    public void addListSelectionListener(ListSelectionListener listener) {
        this.filteredList.addListSelectionListener(listener);
    }
    
    public void addSelectionInterval(int anchor, int lead) {
        this.filteredList.addSelectionInterval(anchor, lead);
    }
    
    public void clearSelection() {
        this.filteredList.clearSelection();
    }
    
    public void ensureIndexIsVisible(int index) {
        this.filteredList.ensureIndexIsVisible(index);
    }
    
    public ListCellRenderer getCellRenderer() {
        return this.filteredList.getCellRenderer();
    }
    
    public MouseListener[] getListMouseListeners() {
        return this.filteredList.getMouseListeners();
    }
    
    public MouseMotionListener[] getListMouseMotionListeners() {
        return this.filteredList.getMouseMotionListeners();
    }
    
    public ListSelectionListener[] getListSelectionListeners() {
        return this.filteredList.getListSelectionListeners();
    }
    
    public int getMaxSelectionIndex() {
        return this.filteredList.getMaxSelectionIndex();
    }
    
    public int getMinSelectionIndex() {
        return this.filteredList.getMinSelectionIndex();
    }
    
    public int getSelectedIndex() {
        return this.filteredList.getSelectedIndex();
    }
    
    public int[] getSelectedIndices() {
        return this.filteredList.getSelectedIndices();
    }
    
    public Object getSelectedValue() {
        return this.filteredList.getSelectedValue();
    }
    
    public Object[] getSelectedValues() {
        return this.filteredList.getSelectedValues();
    }
    
    public int getSelectionMode() {
        return this.filteredList.getSelectionMode();
    }
    
    public boolean isSelectedIndex(int index) {
        return this.filteredList.isSelectedIndex(index);
    }
    
    public boolean isSelectionEmpty() {
        return this.filteredList.isSelectionEmpty();
    }
    
    public void removeListMouseListener(MouseListener l) {
        this.filteredList.removeMouseListener(l);
    }
    
    public void removeListMouseMotionListener(MouseMotionListener l) {
        this.filteredList.removeMouseMotionListener(l);
    }
    
    public void removeListSelectionListener(ListSelectionListener listener) {
        this.filteredList.removeListSelectionListener(listener);
    }
    
    public void removeSelectionInterval(int index0, int index1) {
        this.filteredList.removeSelectionInterval(index0, index1);
    }
    
    public void setCellRenderer(ListCellRenderer cellRenderer) {
        this.filteredList.setCellRenderer(cellRenderer);
    }
    
    public void setSelectedIndex(int index) {
        this.filteredList.setSelectedIndex(index);
    }
    
    public void setSelectedIndices(int[] indices) {
        this.filteredList.setSelectedIndices(indices);
    }
    
    public void setSelectedValue(Object anObject, boolean shouldScroll) {
        this.filteredList.setSelectedValue(anObject, shouldScroll);
    }
    
    public void setSelectionInterval(int anchor, int lead) {
        this.filteredList.setSelectionInterval(anchor, lead);
    }
    
    public void setSelectionMode(int selectionMode) {
        this.filteredList.setSelectionMode(selectionMode);
    }
    
    public void setVisibleRowCount(int visibleRowCount) {
        this.filteredList.setVisibleRowCount(visibleRowCount);
    }
}
